package judesart.app.repository;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import javax.inject.Inject;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;

import judesart.app.domain.Artwork;
import judesart.app.domain.Image;
import judesart.app.domain.Note;
import judesart.app.domain.Project;
import judesart.app.domain.ProjectArtwork;
import judesart.app.domain.ProjectPhoto;
import judesart.app.domain.Sketch;
import judesart.app.shared.ValidationException;
import judesart.app.validation.AppValidator;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

@Repository
public class ProjectDAOImpl implements ProjectDAO {
    private final static Log LOGGER = LogFactory.getLog(ProjectDAOImpl.class);

    @PersistenceContext
    private EntityManager entityManager;

    @Inject
    private AppValidator validator;

    @Inject
    private ImageDAO imageDAO;

    @Override
    @Transactional(propagation = Propagation.REQUIRED)
    public Project addArtworkToProject(Project project, Artwork artwork) {
        project = entityManager.merge(project);
        if (project.getArtworks() == null) {
            project.setArtworks(new ArrayList<ProjectArtwork>());
        }
        for (ProjectArtwork projArt : project.getArtworks()) {
            if (projArt.getArtworkId().longValue() == artwork.getId()
                    .longValue()) {
                return project;
            }
        }
        ProjectArtwork projectArtwork = new ProjectArtwork();
        projectArtwork.setArtworkId(artwork.getId());
        projectArtwork.setProject(project);
        project.getArtworks().add(projectArtwork);
        entityManager.flush();
        return project;
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED)
    public Project addNoteToProject(Project project, String noteText) {
        project = entityManager.merge(project);
        Note note = new Note();
        note.setCreatedAt(new Date());
        note.setText(noteText);
        note.setProject(project);
        if (project.getNotes() == null) {
            project.setNotes(new ArrayList<Note>());
        }
        project.getNotes().add(note);
        entityManager.flush();
        return project;
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED)
    public Project addPhotoToProject(Project project, String fileName,
            String blobKey) {
        Image image = new Image();
        image.setBlobKey(blobKey);
        image.setName(fileName);
        image = imageDAO.createImage(image);
        project = entityManager.merge(project);
        ProjectPhoto photo = new ProjectPhoto();
        photo.setProject(project);
        photo.setImageId(image.getId());
        if (project.getPhotos() == null) {
            project.setPhotos(new ArrayList<ProjectPhoto>());
        }
        project.getPhotos().add(photo);
        entityManager.flush();
        return project;
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED)
    public Project addSketchToProject(Project project, String fileName,
            String blobKey) {
        Image image = new Image();
        image.setBlobKey(blobKey);
        image.setName(fileName);
        image = imageDAO.createImage(image);
        project = entityManager.merge(project);
        Sketch sketch = new Sketch();
        sketch.setProject(project);
        sketch.setImageId(image.getId());
        if (project.getSketchs() == null) {
            project.setSketchs(new ArrayList<Sketch>());
        }
        project.getSketchs().add(sketch);
        entityManager.flush();
        return project;
    }

    @Override
    public int countProjects(Long artistId) {
        return (Integer) entityManager.createNamedQuery(
                "Project.countByArtistId").setParameter("artistId", artistId)
                .getSingleResult();
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED)
    public Project createProject(Project project) throws ValidationException {
        validator.validate(project);
        entityManager.persist(project);
        entityManager.flush();
        return project;
    }

    @SuppressWarnings("unchecked")
    @Override
    @Transactional(propagation = Propagation.REQUIRED)
    public List<Long> findProjectIdsByArtworkId(Long artworkId) {
        List<Project> projects = entityManager.createNamedQuery(
                "ProjectArtwork.findProjectsByArtworkId").setParameter(
                "artworkId", artworkId).getResultList();
        List<Long> result = new ArrayList<Long>();
        for (Project project : projects) {
            result.add(project.getId());
        }
        return result;
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED)
    public Project deleteArtworkFromProject(Project project, Artwork artwork) {
        project = entityManager.merge(project);
        ProjectArtwork found = null;
        for (ProjectArtwork projArt : project.getArtworks()) {
            if (projArt.getArtworkId().longValue() == artwork.getId()
                    .longValue()) {
                found = projArt;
                break;
            }
        }
        if (found != null) {
            project.getArtworks().remove(found);
        }
        entityManager.flush();
        return project;
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED)
    public Project deleteNoteFromProject(Project project, String noteKey) {
        project = entityManager.merge(project);
        Note found = null;
        for (Note note : project.getNotes()) {
            if (noteKey.equals(note.getKey())) {
                found = note;
                break;
            }
        }
        if (found != null) {
            project.getNotes().remove(found);
        }
        entityManager.flush();
        return project;
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED)
    public Project deletePhotoFromProject(Project project, Long photoId) {
        Image image = imageDAO.deleteImage(photoId);
        if (image != null) {
            project = entityManager.merge(project);
            List<ProjectPhoto> photos = project.getPhotos();
            ProjectPhoto found = null;
            for (ProjectPhoto photo : photos) {
                if (photo.getImageId().equals(photoId)) {
                    found = photo;
                    break;
                }
            }
            if (found != null) {
                project.getPhotos().remove(found);
            }
            entityManager.flush();
        }
        return project;
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED)
    public void deleteProject(Long projectId) {
        Project project = entityManager.find(Project.class, projectId);
        entityManager.remove(project);
        entityManager.flush();
        if (project.getPhotos() != null) {
            for (ProjectPhoto photo : project.getPhotos()) {
                imageDAO.deleteImage(photo.getImageId());
            }
        }
        if (project.getSketchs() != null) {
            for (Sketch sketch : project.getSketchs()) {
                imageDAO.deleteImage(sketch.getImageId());
            }
        }
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED)
    public Project deleteSketchFromProject(Project project, Long photoId) {
        Image image = imageDAO.deleteImage(photoId);
        if (image != null) {
            project = entityManager.merge(project);
            List<Sketch> sketchs = project.getSketchs();
            Sketch found = null;
            for (Sketch sketch : sketchs) {
                if (sketch.getImageId().equals(photoId)) {
                    found = sketch;
                    break;
                }
            }
            if (found != null) {
                project.getSketchs().remove(found);
            }
            entityManager.flush();
        }
        return project;
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED)
    public Project findProjectById(Long projectId) {
        LOGGER.debug(" >> findProjectById [" + projectId + "]");
        Project project = entityManager.find(Project.class, projectId);
        loadProjectDependencies(project);
        return project;
    }

    @SuppressWarnings("unchecked")
    @Override
    @Transactional(propagation = Propagation.REQUIRED)
    public List<Project> findProjects(Long artistId, int startAt,
            int maxElements) {
        List<Project> result = entityManager.createNamedQuery(
                "Project.findByArtistId").setParameter("artistId", artistId)
                .setFirstResult(startAt).setMaxResults(maxElements)
                .getResultList();
        loadProjectsDependencies(result);
        return result;
    }

    private void loadProjectsDependencies(List<Project> result) {
        for (Project project : result) {
            loadProjectDependencies(project);
        }
    }

    private void loadProjectDependencies(Project project) {
        for (ProjectArtwork pa : project.getArtworks()) {

        }
        for (Sketch sketch : project.getSketchs()) {

        }
        for (ProjectPhoto photo : project.getPhotos()) {

        }
        for (Note note : project.getNotes()) {

        }
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED)
    public Note updateNoteText(String noteKey, String noteText) {
        Note note = entityManager.find(Note.class, noteKey);
        note.setText(noteText);
        entityManager.flush();
        return note;
    }

    @Override
    public String findProjectKeyByImageId(Long imageId) {
        return (String) entityManager.createNamedQuery(
                "ProjectPhoto.findKeyByImageId").setParameter("imageId",
                imageId).getSingleResult();
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED)
    public ProjectPhoto updatePhotoDescription(String photoKey,
            String description) {
        ProjectPhoto photo = entityManager.find(ProjectPhoto.class, photoKey);
        photo.setDescription(description);
        entityManager.flush();
        return photo;
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED)
    public Project updateProject(Project project) throws ValidationException {
        validator.validate(project);
        project = entityManager.merge(project);
        entityManager.flush();
        return project;
    }

    @Override
    public String findSketchKeyByImageId(Long imageId) {
        return (String) entityManager.createNamedQuery(
                "Sketch.findKeyByImageId").setParameter("imageId", imageId)
                .getSingleResult();
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED)
    public Sketch updateSketchDescription(String sketchKey, String description) {

        Sketch sketch = entityManager.find(Sketch.class, sketchKey);
        sketch.setDescription(description);
        entityManager.flush();
        return sketch;
    }

}
